#ifndef ELEMENTS_H_
#define ELEMENTS_H_

#include <stdio.h>
#include <stdlib.h>



/* Nodes */

struct struct_node {
      int position[2];
      struct list_nodes* neighbours; /* Each node handle a list of his neighbours*/
      char* label;
      int type;                      /* 1: Real node - 2: bend or segment - */
      int number;
      struct struct_node* n1;
      struct struct_node* n2;
};
typedef struct struct_node node;

struct list_nodes {
      node* node;
      struct list_nodes* next;
};
typedef struct list_nodes list_nodes;

struct list_lists_nodes {
      list_nodes* list_nodes;
      struct list_lists_nodes* next;
};
typedef struct list_lists_nodes list_lists_nodes;

void insert_node_at_top(list_nodes** first, node* node);
	/* Add a node at the end of a node-list */


/* Arcs and real arcs*/

struct struct_arc{
      node* n1;
      node* n2;
      int degree; /* Number of couple of nodes with the same positions*/
};
typedef struct struct_arc arc;


struct list_arcs {
      arc* arc;
      struct list_arcs* next;
};
typedef struct list_arcs list_arcs;

struct list_real_arcs {
      list_nodes* nodes;
      node* n_start;
      node* n_end;
      int length;
      struct list_real_arcs* next;
};
typedef struct list_real_arcs list_real_arcs;



/* Grids */

struct struct_grid {
      int dims[2]; /* Dimensions of the grid (we use only width and height, the first two)*/
      list_nodes*** cells; /* In each cell we estabilish there can be more than one node */

};
typedef struct struct_grid grid;








int is_empty_list (void ** first);
/* Verifies if a list is empty */



/* Arcs */

void insert_arc(list_arcs** first, arc* arc);
/* Add a arc at the and of an arc-list */


int delete_arc_from_list(list_arcs** first, arc* n);
/* Deletes an arc from arc-list*/



int length_list_arcs( list_arcs* list);
/* Returns the length of list_arcs  */

int is_in_list_arcs(list_arcs* in_arcs, arc* arc);
/* It verifies if arc is in list_arcs */

list_arcs* copy_list_arcs(list_arcs* list);
/* Returns a copy of a arc list */

list_arcs* conc_list_arcs(list_arcs* l1, list_arcs** l2);
/* Concatenates two different list_arcs and returns the fusion one */
 
void conc_list_arcs2(list_arcs* l1, list_arcs** l2);
/* Concatenates two different list_arcs and returns the fusion one */

arc* create_arc(node* n1, node*n2);
/* It creates and returns an arc */

list_arcs* make_arcs(node* n, list_nodes* ln, list_nodes* visited );
/* Given a node and his neighbours, it creates a list of arcs only if the node isn't in visited list
  (to avoid a copy of the same arc in reverse direction */


void free_list_arcs( list_arcs* list );
/* It frees memory occupied by list_nodes */

 
void free_list_real_arcs( list_real_arcs* list );
/* It frees memory occupied by list_nodes */

void free_node(node**, int);

/* Nodes */

void insert_node(list_nodes** first, node* node);
/* Add a node at the end of a node-list */

int delete_node_from_list(list_nodes** first, node* n);


list_nodes* get_neighbours(node* n, int x, int y);
/* Returns neighbours of a node in the cell (x,y)*/

int length_nodes_list(list_nodes* list);
/* Returns length of nodes*/

void free_list_nodes( list_nodes* list, int mode );
/* It frees memory occupied by list_nodes */

node* create_node(char* label, int type);
/* It creates a new node */
      
node* create_node_in_cell(grid* gr, char* label, int type, int x, int y);

list_nodes* copy_list_nodes( list_nodes* list );
/* Returns a copy of a node list */

int is_in_list_nodes(list_nodes* first, node* n);
/* It verifies if node n is in the list_nodes*/

void make_neighbour( node* n1, node* neigh );
/* Puts n1 node as a neighbour of neigh node and viceversa*/
            
void clear_node_neighbours(node* n);
/* It clears neighbours list of node n*/

void conc_list_nodes2(list_nodes* l1, list_nodes** l2);
/* Concatenates two different list_nodes and returns the fusion one*/
      
list_nodes* conc_nodes(list_nodes* l1, list_nodes* l2);
/* Concatenates two different list_nodes and returns the fusion one*/

list_nodes* conc_nodes_to_set(list_nodes* l1, list_nodes* l2);
/* Concatenates two different list_nodes and returns the fusion one, verifying to delete duplicates */
      
int is_in_positions(int positions[4][2], int num_pos, int x, int y);
/* Verifies if a node is in one of the positions */

void near_positions(grid* gr, int positions[4][2], int x, int y );
/* Returns grid positions around an x,y tuple of coordinates. 
 * It considers the special cases of positions at grid borders, 
 * putting NULL some position when a cell is at the borders*/

int has_neighbour(node* n, int x, int y);
/* Gived a node, this function estabilishes if the node has neighbours with position (x,y) */
      


/* Grids */

grid* create_2d_empty_grid( int width, int height );
/* Creates a width x, height y grid with all cells to NULL and returns a pointer to it */
      
void put_node_in_cell(node* n1, grid* gr, int x, int y );

int free_grid(grid* gr);

void delete_nodes_from_cell (grid* gr, int x, int y);


int is_real_node_in_cell(grid* gr, int x, int y); 
/* It estabilishes if there is a real node in a cell */

      

/* Printing */

void print_list_nodes(list_nodes* list);

void print_real_arcs( list_real_arcs* real_arcs );

void print_list_arcs(list_arcs* list);

void print_2d_grid( grid* gr );

void print_labels(node* n );

#endif /*ELEMENTS_H_*/
















